using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;

namespace OverSizeImage
{
    public class RotateAdorner : UserControl
    {
        Thumb middleThumb, rotateThumb;

        Grid _grid;

        double InitSzie = 10.0;

        public double ScaleValue
        {
            get { return (double)GetValue(ScaleValueProperty); }
            set { SetValue(ScaleValueProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ScaleValue.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ScaleValueProperty =
            DependencyProperty.Register("ScaleValue", typeof(double), typeof(RotateAdorner), new PropertyMetadata(1.0, (sender, e) =>
            {
                var dp = sender as RotateAdorner;
                if (dp == null) return;
                dp.ScaleChanged();
            }));

        public Brush ThumbBrush
        {
            get { return (Brush)GetValue(ThumbBrushProperty); }
            set { SetValue(ThumbBrushProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ThumbBrush.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ThumbBrushProperty =
            DependencyProperty.Register("ThumbBrush", typeof(Brush), typeof(RotateAdorner), new PropertyMetadata(Brushes.White));



        private void ScaleChanged()
        {
            rotateThumb.Width = InitSzie / ScaleValue;
            rotateThumb.Height = InitSzie / ScaleValue;
        }

        public double X
        {
            get { return (double)GetValue(XProperty); }
            set { SetValue(XProperty, value); }
        }

        // Using a DependencyProperty as the backing store for X.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty XProperty =
            DependencyProperty.Register("X", typeof(double), typeof(RotateAdorner), new UIPropertyMetadata(0.0));

        public double Y
        {
            get { return (double)GetValue(YProperty); }
            set { SetValue(YProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Y.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty YProperty =
            DependencyProperty.Register("Y", typeof(double), typeof(RotateAdorner), new UIPropertyMetadata(0.0));


        public double Angle
        {
            get { return (double)GetValue(AngleProperty); }
            set { SetValue(AngleProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Angle.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty AngleProperty =
            DependencyProperty.Register("Angle", typeof(double), typeof(RotateAdorner), new UIPropertyMetadata(0.0));



        public bool HitEnabled
        {
            get { return (bool)GetValue(HitEnabledProperty); }
            set { SetValue(HitEnabledProperty, value); }
        }

        // Using a DependencyProperty as the backing store for HitEnabled.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty HitEnabledProperty =
            DependencyProperty.Register("HitEnabled", typeof(bool), typeof(RotateAdorner), new PropertyMetadata(false));




        public RotateAdorner()
        {
            rotateThumb = new Thumb();
            rotateThumb.HorizontalAlignment = HorizontalAlignment.Center;
            rotateThumb.VerticalAlignment = VerticalAlignment.Center;
            rotateThumb.Cursor = Cursors.Cross;

            middleThumb = new Thumb();
            middleThumb.HorizontalAlignment = HorizontalAlignment.Stretch;
            middleThumb.VerticalAlignment = VerticalAlignment.Stretch;
            middleThumb.Cursor = Cursors.Hand;

            _grid = new Grid();
            _grid.Children.Add(middleThumb);
            Binding bind = new Binding();
            bind.Source = this;
            bind.Path = new PropertyPath("HitEnabled");
            bind.Mode = BindingMode.TwoWay;
            bind.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
            middleThumb.SetBinding(Thumb.IsHitTestVisibleProperty, bind);
            middleThumb.Background = Brushes.Gray;
            middleThumb.Opacity = 0.01;
            middleThumb.Template = new ControlTemplate(typeof(Thumb))
            {
                VisualTree = GetWholeFactory(ThumbBrush)
            };
            middleThumb.DragDelta += Thumb_DragDelta;

            _grid.Children.Add(rotateThumb);
            InitThumb(rotateThumb);

            AddVisualChild(_grid);
        }



        private void InitThumb(Thumb thumb)
        {
            thumb.Width = InitSzie;
            thumb.Height = InitSzie;
            thumb.Background = Brushes.Green;
            thumb.Template = new ControlTemplate(typeof(Thumb))
            {
                VisualTree = GetFactory(ThumbBrush)
            };
            thumb.DragDelta += Thumb_DragDelta;
        }

        protected override Visual GetVisualChild(int index)
        {
            return _grid;
        }

        protected override int VisualChildrenCount
        {
            get { return 1; }
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            _grid.Arrange(new Rect(new Point(-InitSzie / 2, -InitSzie / 2),
                new Size(finalSize.Width + InitSzie, finalSize.Height + InitSzie)));
            return finalSize;
        }

        private void Thumb_DragDelta(object sender, DragDeltaEventArgs e)
        {
            var thumb = sender as FrameworkElement;
            if (thumb.HorizontalAlignment == HorizontalAlignment.Stretch && thumb.VerticalAlignment == VerticalAlignment.Stretch)
            {
                X += e.HorizontalChange;
                Y += e.VerticalChange;
                return;
            }

            if (thumb.HorizontalAlignment == HorizontalAlignment.Center && thumb.VerticalAlignment == VerticalAlignment.Center)
            {
                Point currentLocation = Mouse.GetPosition(this);
                Point knobCenter = new Point(this.ActualWidth / 2, this.ActualHeight / 2);

                double radians = Math.Atan((currentLocation.Y - knobCenter.Y) / (currentLocation.X - knobCenter.X));
                var angle = radians * 180 / Math.PI;
                Angle = angle % 360;
                return;
            }
        }

        private FrameworkElementFactory GetFactory(Brush back)
        {
            var fef = new FrameworkElementFactory(typeof(Ellipse));
            fef.SetValue(Ellipse.FillProperty, back);
            return fef;
        }

        private FrameworkElementFactory GetWholeFactory(Brush back)
        {
            var fef = new FrameworkElementFactory(typeof(Rectangle));
            fef.SetValue(Ellipse.FillProperty, back);
            return fef;
        }
    }
}
